float4x4 World;
float4x4 View;
float4x4 Projection;

float	Alpha;					// The alpha channel of the material to be drawn.

float4	AmbientColor;			// The color of the ambient light.
float	AmbientIntensity;		// The intensity of the ambient light.

float3	DiffuseLightDirection;	// The direction of the light.
float4	DiffuseColor;			// The diffuse light color.
float	DiffuseIntensity;		// The diffuse light intensity.

float	SpecularPower;			// The "shininess" of the material. A larger value gives a small and intense specular highlight.
float4	SpecularColor;			// The color of the specular highlight.
float	SpecularIntensity;		// The intensity of the specular highlight.

float3	ViewVector;				// The direction the viewer is looking in.
float3	EyePosition;			// The position of the viewer.

float	GroundAltitudeStart;	// The altitude where mud should end and the ground blending should start.
float	GroundAltitudeEnd;		// The altitude where the ground blending should end and the ground should start.
float	MountainAltitudeStart;	// The altitude where ground should end and the mountain blending should start.
float	MountainAltitudeEnd;	// The altitude where the mountain blending should end and the mountain should start.
float Time;
uniform extern int CircleCount;
uniform const float CircleBlendWidth = 9;
uniform extern float2 CirclePositions[3];
uniform const float CircleRadii[3];

texture GroundTexture;
sampler2D groundSampler = sampler_state
{
	Texture = (GroundTexture);
	MipFilter = ANISOTROPIC;
	MinFilter = ANISOTROPIC;
	MagFilter = ANISOTROPIC;
    AddressU = Wrap;
    AddressV = Wrap;
};

texture MountainTexture;
sampler2D mountainSampler = sampler_state
{
	Texture = (MountainTexture);
	MipFilter = ANISOTROPIC;
	MinFilter = ANISOTROPIC;
	MagFilter = ANISOTROPIC;
    AddressU = Wrap;
    AddressV = Wrap;
};

texture MudTexture;
sampler2D mudSampler = sampler_state
{
	Texture = (MudTexture);
	MipFilter = ANISOTROPIC;
	MinFilter = ANISOTROPIC;
	MagFilter = ANISOTROPIC;
    AddressU = Wrap;
    AddressV = Wrap;
};

texture CliffTexture;
sampler2D cliffSampler = sampler_state
{
	Texture = (CliffTexture);
	MipFilter = ANISOTROPIC;
	MinFilter = ANISOTROPIC;
	MagFilter = ANISOTROPIC;
    AddressU = Wrap;
    AddressV = Wrap;
};

texture FogTexture;
sampler2D fogSampler = sampler_state
{
	Texture = (FogTexture);
	MipFilter = ANISOTROPIC;
	MinFilter = ANISOTROPIC;
	MagFilter = ANISOTROPIC;
    AddressU = Wrap;
    AddressV = Wrap;
};

// TODO: add effect parameters here.

struct VertexShaderInput
{
    float4 Position				: POSITION0;
    float3 Normal				: NORMAL0;
	float2 TextureCoordinate	: TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position				: POSITION0;
    float2 TextureCoordinate	: TEXCOORD0;
    float3 Normal				: TEXCOORD1;
    float4 WorldPosition		: TEXCOORD2;
};

float InCircle(float2 position)
{
	int i = 0;
	float dist, innerRadius, blendFactor;
	float minBlendFactor = 1;
	do
	{
		dist = distance(CirclePositions[i], position);
		if(dist <= CircleRadii[i])
		{
			// inner radius denotes the radius at which point the fog disappears completely.
			// Any fragment that lies in between the inner and outer radius will be blended
			// with "a certain degree of fog".
			innerRadius = CircleRadii[i] - CircleBlendWidth;
			
			// blendfactor will be a value ranging from 0 to 1. 1 If this fragment is exactly ON
			// the radius of the circle, and 0 if the fragment is within the inner radius.
			blendFactor = saturate((dist - innerRadius) / (CircleRadii[i] - innerRadius));
			
			// Find the smallest blendfactor.
			if(blendFactor < minBlendFactor)
				minBlendFactor = blendFactor;
				
			//break;
		}
	i++;
	} while(i < CircleCount);

	return minBlendFactor;
}

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    
    output.Position = mul(viewPosition, Projection);
    output.TextureCoordinate = input.TextureCoordinate;
    output.Normal = normalize(mul(input.Normal, World));
    output.WorldPosition = worldPosition;

    return output;
}

float4 PSTexture(VertexShaderOutput input) : COLOR0
{
	//return float4(0,1,0,1);
	float3 N = normalize(input.Normal);
    //----------------------- Calculate terrain texture ------------------
    float4 textureColor;
    if(input.WorldPosition.y < GroundAltitudeStart){
		textureColor = tex2D(mudSampler, input.TextureCoordinate);
    }
    else if(input.WorldPosition.y > GroundAltitudeStart && input.WorldPosition.y < GroundAltitudeEnd){
		float factor = saturate((input.WorldPosition.y - GroundAltitudeStart) / (GroundAltitudeEnd - GroundAltitudeStart));

		textureColor = lerp(tex2D(mudSampler, input.TextureCoordinate), tex2D(groundSampler, input.TextureCoordinate), factor);
    }
    else if(input.WorldPosition.y > GroundAltitudeEnd && input.WorldPosition.y < MountainAltitudeStart){
    	textureColor = tex2D(groundSampler, input.TextureCoordinate);
    }
    else if(input.WorldPosition.y > MountainAltitudeStart && input.WorldPosition.y < MountainAltitudeEnd){
      	float factor = saturate((input.WorldPosition.y - MountainAltitudeStart) / (MountainAltitudeEnd - MountainAltitudeStart));
		textureColor = lerp(tex2D(groundSampler, input.TextureCoordinate), tex2D(mountainSampler, input.TextureCoordinate), factor);
    }
    else{
		textureColor = tex2D(mountainSampler, input.TextureCoordinate);
    }
    
    	//----------------------- Calculate lighting ------------------
    // Calculate the diffuse light component with the bump map normal
    float diffuseIntensity = dot(normalize(DiffuseLightDirection), N);
    if(diffuseIntensity < 0.4)
        diffuseIntensity = 0.4;

    // Calculate the specular light component with the bump map normal
    float3 light = normalize(DiffuseLightDirection);
    float3 r = normalize(2 * dot(light, N) * N - light);
    float3 v = normalize(mul(normalize(ViewVector), World));
    float dotProduct = dot(r, v);
 
    float4 specular = SpecularIntensity * SpecularColor * max(pow(dotProduct, SpecularPower), 0);
 
    
    //----------------------- Cliff blending ------------------
    // Blend the terrain texture with the cliff texture, based on the slope of the surface.
    textureColor = lerp(textureColor, tex2D(cliffSampler, input.TextureCoordinate), 1-N.y);
    textureColor.a = Alpha;
    
	// Blend it all together.
	float4 color = saturate(textureColor * (diffuseIntensity) + (AmbientColor * AmbientIntensity) + specular);
	
    return color;
}

float4 PSColor(VertexShaderOutput input) : COLOR0
{
    // Calculate the diffuse light component with the bump map normal
    float diffuseIntensity = dot(normalize(DiffuseLightDirection), input.Normal);
    if(diffuseIntensity < 0.0)
        diffuseIntensity = 0.0;
 
    // Calculate the specular light component with the bump map normal
    float3 light = normalize(DiffuseLightDirection);
    float3 r = normalize(2 * dot(light, input.Normal) * input.Normal - light);
    float3 v = normalize(mul(normalize(ViewVector), World));
    float dotProduct = dot(r, v);
 
    float4 specular = SpecularIntensity * SpecularColor * max(pow(dotProduct, SpecularPower), 0) * diffuseIntensity;
 
    // Calculate the texture color
    float4 textureColor = DiffuseColor;
    textureColor.a = Alpha;
//    float fogFactor = FogEnabled * saturate((length(EyePosition-input.WorldPosition) -FogStart) /(FogEnd-FogStart)); 
	float4 color = saturate(textureColor * (diffuseIntensity) + AmbientColor * AmbientIntensity + specular);
	//color.rgb = lerp(color.rgb, FogColor, fogFactor);
	//return float4(input.Normal, 1);
    return color;
}

int PixelShaderIndex = 0;

technique Technique1
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PSTexture();
    }
}
